import 'dart:async';

import 'package:amplitude_flutter/amplitude.dart';
import 'package:equatable/equatable.dart';
import 'package:mobile_app.core/core/domain/config/config.dart';
import 'package:mobile_app.core/core/domain/entities/purchase_offer_source.dart';
import 'package:mobile_app.core/core/domain/services/analytics_service/service.dart';
import 'package:mobile_app.core/crashlytics/crashlytics.dart';
import 'package:mobile_app.core/logger/logger.dart';

part 'dtos/purchase_offer_source_dto.dart';

class AnalyticsServiceImpl implements AnalyticsService {
  const AnalyticsServiceImpl({
    required Amplitude amplitude,
  }) : _amplitude = amplitude;

  final Amplitude _amplitude;

  @override
  Future<void> initialize({
    required String? userId,
  }) async {
    await _initializeAmplitude(
      userId: userId,
    );
  }

  @override
  void setTracking(bool trackingEnabled) {
    try {
      _amplitude.setOptOut(!trackingEnabled).timeout(const Duration(seconds: 2));
    } catch (e, s) {
      Logger().e(null, e, s);

      Crashlytics().recordError(
        error: e,
        stackTrace: s,
        fatal: false,
      );
    }
  }

  @override
  void setDeviceId(String deviceId) {
    try {
      _amplitude.setDeviceId(deviceId).timeout(const Duration(seconds: 2));
    } catch (e, s) {
      Logger().e(null, e, s);

      Crashlytics().recordError(
        error: e,
        stackTrace: s,
        fatal: false,
      );
    }
  }

  @override
  void setUserId(String? userId) {
    try {
      _amplitude.setUserId(userId).timeout(const Duration(seconds: 2));
    } catch (e, s) {
      Logger().e(null, e, s);

      Crashlytics().recordError(
        error: e,
        stackTrace: s,
        fatal: false,
      );
    }
  }

  @override
  void setDeviceCountryCode(String deviceCountryCode) {
    _amplitude.setUserProperties({
      'device country code': deviceCountryCode,
    });
  }

  Future<void> _initializeAmplitude({
    required String? userId,
  }) async {
    try {
      await _amplitude
          .init(Config().amplitudeApiKey, userId: userId)
          .timeout(const Duration(seconds: 2));
    } catch (e, s) {
      Logger().e(null, e, s);

      Crashlytics().recordError(
        error: e,
        stackTrace: s,
        fatal: false,
      );
    }
  }

  @override
  void logFirstLaunch() {
    _amplitude.logEvent('first launch');
  }

  @override
  void logIntroStart() {
    _amplitude.logEvent('intro started');
  }

  @override
  void logIntroWelcomePass() {
    _amplitude.logEvent('intro welcome passed');
  }

  @override
  void logIntroFinish() {
    _amplitude.logEvent('intro finished');
  }

  @override
  void logReviewRequest() {
    _amplitude.logEvent('review requested');
  }

  @override
  void logTrainingCompletion() {
    _amplitude.logEvent('training completed');
  }

  @override
  void logPurchaseOffer({
    required PurchaseOfferSource purchaseOfferSource,
  }) {
    final purchaseSourceDto = _PurchaseOfferSourceDto.fromEntity(purchaseOfferSource);
    final purchaseSourceString = purchaseSourceDto.toString();

    _amplitude.logEvent(
      'purchases offered',
      eventProperties: {
        'source': purchaseSourceString,
      },
    );
  }

  @override
  void logPurchaseFlowStart({
    required PurchaseOfferSource purchaseOfferSource,
  }) {
    final purchaseOfferSourceDto = _PurchaseOfferSourceDto.fromEntity(purchaseOfferSource);
    final purchaseOfferSourceString = purchaseOfferSourceDto.toString();

    _amplitude.logEvent(
      'purchase flow started',
      eventProperties: {
        'source': purchaseOfferSourceString,
      },
    );
  }

  @override
  void logPurchaseFlowCancellation() {
    _amplitude.logEvent('purchase flow cancelled');
  }

  @override
  void logPurchaseFlowFailure({
    required String message,
  }) {
    _amplitude.logEvent(
      'purchase flow failed',
      eventProperties: {
        'message': message,
      },
    );
  }
}
